home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / GNU Diff Sources / MacMain.c next >
Encoding:
C/C++ Source or Header  |  1992-11-14  |  50.6 KB  |  1,983 lines  |  [TEXT/ALFA]

  1. /* Support routines for GNU DIFF.
  2.    Copyright (C) 1988 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU DIFF.
  5.  
  6. GNU DIFF is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY.  No author or distributor
  8. accepts responsibility to anyone for the consequences of using it
  9. or for whether it serves any particular purpose or works at all,
  10. unless he says so in writing.  Refer to the GNU DIFF General Public
  11. License for full details.
  12.  
  13. Everyone is granted permission to copy, modify and redistribute
  14. GNU DIFF, but only under the conditions described in the
  15. GNU DIFF General Public License.   A copy of this license is
  16. supposed to have been given to you along with GNU DIFF so you
  17. can know your rights and responsibilities.  It should be in a
  18. file named COPYING.  Among other things, the copyright notice
  19. and this notice must be preserved on all copies.  */
  20.  
  21. #include    <MacHeaders>
  22. #include    <Packages.h>
  23. #include    <stdarg.h>
  24. #define    GDIFF_MAIN
  25. #include "diff.h"
  26. #include    "diff3.h"
  27. #include    "regex.h"
  28.  
  29. int    no_discards;
  30.  
  31. int    allocatedBlocks = 0;
  32.  
  33. #include    "QuedProcs.h"
  34.  
  35. void    _main(void);    /* Called at startup. */
  36.  
  37. /*
  38.  * These are the callbacks that the "diff" module changes.  The following global variables hold
  39.  * the original callback routines, so that we can call them when needed.  Each one is overridden
  40.  * the the same function name except preceeded with the word "Diff".  For example, ReadPreferences
  41.  * is overridden with "DiffReadPreferences".  Its original procedure pointer is stored in "OriginalReadPreferences".
  42.  */
  43. /*
  44.  * We need to save more preferences, so that we can remember what the settings were next time
  45.  * the program starts up.
  46.  */
  47. static    void    (*OriginalReadPreferences) (void);
  48. static    void    (*OriginalSavePreferences) (void);
  49. /*
  50.  * We need to move more text markers when text is inserted and deleted.  This way, the change bars on
  51.  * the left side are updated when text is inserted, etc.
  52.  */
  53. static    int        (*OriginalOffsetTextMarkers) (VTE, long location, long numDelete, long numInsert);
  54. /*
  55.  * We modify the ShowLeftMarginIcons, GetQuedIconsWidth, and ClickLeftMarginIcons so that the change
  56.  * bars will appear on the left side of the windows that have been run through a "diff".
  57.  */
  58. static    int        (*OriginalShowLeftMarginIcons) (VTE, long startl, long end, Rect *lineRect, int iconPosition);
  59. static    int        (*OriginalGetQuedIconsWidth) (VTE);
  60. static    int        (*OriginalClickLeftMarginIcons) (VTE w, long sel, Point where, int *barPosition);
  61. /*
  62.  * Since the "diff" module adds supplemental information to a window, it needs to dispose that information
  63.  * when that window is closed.  Overriding the dispose procedure for a window allows us to do this.
  64.  */
  65. static    void    (*OriginalKillTextWindow) (VTE);
  66. /*
  67.  * This is the end of the functions and procedures we override.
  68.  */
  69.  
  70. /*
  71.  * These are the items in the "Two Files:" popup menu that appears in the
  72.  * Differences Options... dialog.
  73.  */
  74. enum    CompareResult2
  75.     {
  76.     cShowChangeBars2,
  77.     cComposite2,
  78.     cIfdef2,
  79.     cUNIX2,
  80.     cUnified2,
  81.     cED2,
  82.     cForwardED2,
  83.     cRCS2
  84.     };
  85.  
  86. /*
  87.  * These are the items in the "Three Files:" popup menu that appears in the
  88.  * Differences Options... dialog.
  89.  */
  90. enum    CompareResult3
  91.     {
  92.     cShowChangeBars3,
  93.     cComposite3,
  94.     cMerge3,
  95.     cUNIX3
  96.     };
  97.  
  98. /*
  99.  * These are the item numbers of each item in the Differences Options... dialog.
  100.  */
  101. enum    DiffOptionsDialogItems
  102.     {
  103.     DITEM_OK = 1,
  104.     DITEM_CANCEL,
  105.     DITEM_STAT3,
  106.     DITEM_STAT4,
  107.     DITEM_MULTBLANK,
  108.     DITEM_ALLBLANK,
  109.     DITEM_BLANKLINES,
  110.     DITEM_CASE,
  111.     DITEM_LINESCONTAINING,
  112.     DITEM_EDITLINESCONTAINING,
  113.     DITEM_FASTCOMPARE,
  114.     DITEM_STAT12,
  115.     DITEM_STAT13,
  116.     DITEM_TWOFILES,
  117.     DITEM_STAT15,
  118.     DITEM_THREEFILES,
  119.     DITEM_SHOWCONTEXT,
  120.     DITEM_EDITCONTEXTAMOUNT,
  121.     DITEM_STAT19,
  122.     DITEM_SHOWPRECEEDING,
  123.     DITEM_EDITSHOWPRECEEDING,
  124.     DITEM_USER22,
  125.     DITEM_REPLACETOP,
  126.     DITEM_STAT24,
  127.     DITEM_SHOWCHANGEBARS,
  128.     DITEM_STAT26,
  129.     DITEM_STAT27,
  130.     DITEM_IFDEF,
  131.     DiffOptionsDialogItemsNum,
  132.     DITEM_FIRSTUNIX = DITEM_SHOWCONTEXT,
  133.     DITEM_LASTUNIX = DITEM_EDITSHOWPRECEEDING,
  134.     DITEM_FIRSTWINDOW = DITEM_REPLACETOP,
  135.     DITEM_LASTWINDOW = DITEM_REPLACETOP,
  136.     DITEM_FIRSTSHOWCHANGEBARS = DITEM_SHOWCHANGEBARS,
  137.     DITEM_LASTSHOWCHANGEBARS = DITEM_SHOWCHANGEBARS,
  138.     DITEM_FIRSTIFDEF = DITEM_STAT26,
  139.     DITEM_LASTIFDEF = DITEM_IFDEF
  140.     };
  141.  
  142. /*
  143.  * DIFF_PIXELS is the number of pixels that each change bar column takes up.  Thus, a window
  144.  * with three change bar columns will have 30 pixels for the change bars.
  145.  */
  146. #define    DIFF_PIXELS    10
  147.  
  148. /*
  149.  * When SwapStructureWithDialog is called, the values in this structure
  150.  * are taken from the settings of the items in the Differences Options...
  151.  * dialog, or are deposited to the items in this dialog.
  152.  */
  153. static    struct    DiffOptions
  154.     {
  155.     int    ignoreMultipleBlanks;
  156.     int    ignoreAllBlanks;
  157.     int    ignoreBlankLines;
  158.     int    ignoreCase;
  159.     int    ignoreLinesContaining;
  160.     int    linesContainingLength;
  161.     char    linesContaining[256];
  162.     int    fastCompare;
  163.     int    presentCompareResult2;
  164.     int    presentCompareResult3;
  165.     int    isContext;
  166.     int    contextLines;
  167.     int    linePreceedingIs;
  168.     int    linePreceedingLength;
  169.     char    linePreceeding[256];
  170.     int    replaceTopWindow;
  171.     int    showChangeBars;
  172.     int    ifdefLength;
  173.     char    ifdef[256];
  174.     }    diffOptions;
  175.  
  176. /*
  177.  * This is a Handle to text for stdout.  When something in the "diff" program sends text
  178.  * to stdout or stderr, it gets appended to outFileHandle.
  179.  */
  180. Handle    outFileHandle;
  181.  
  182. /*
  183.  * This is a private structure to the QUED Diff Module.  It stores some information
  184.  * for each change bar.
  185.  */
  186. struct    ChangeBar
  187.     {
  188.     long    start;
  189.     long    end;
  190.     char    whichColumns;        /* These are various flags explaining the type of difference. */
  191.     char    filler;
  192.     int    scriptNumber;
  193.     long    filler2;
  194.     };
  195.  
  196. /* These are the flags for "whichColumns" */
  197. #define    cColumn1    1        /* Put this change in the first column. */
  198. #define    cColumn2    2        /* Put this change in the second column */
  199. #define    cColumn3    4        /* Put this change in the third column */
  200. #define    cFillBlack1    8        /* Fill this one in black.  Indicates a "change" rather than in "insert". */
  201. #define    cFillBlack2    16        /* Fill this one in black.  Indicates a "change" rather than in "insert". */
  202. #define    cFillBlack3    32        /* Fill this one in black.  Indicates a "change" rather than in "insert". */
  203.  
  204. /*
  205.  * This is a private structure to the QUED Diff Module.  It stores some information
  206.  * for each window AFTER that window is run through a "diff".
  207.  */
  208. struct    PrivateWindowData
  209.     {
  210.     VTE    w;
  211.     int    diff1Shown;
  212.     struct    ChangeBar    **diff1Insertions;
  213.     struct    PrivateWindowData    *next;            /* The next in a list of PrivateWindowData */
  214.     VTE    columnWindows[3];
  215.     };
  216.  
  217. /*
  218.  * This is the top of the list to PrivateWindowData.  Whenever a new window is
  219.  * "diff"ed, it is prepended to this list.
  220.  */
  221. struct    PrivateWindowData    *topPrivateWindowData;
  222.  
  223. /*
  224.  * This locates QUED Diff's private window data for a given window, if there is
  225.  * any private window data associated with it.  If there is not, it creates that
  226.  * private window data, and returns it.
  227.  */
  228. static    struct    PrivateWindowData    *
  229. GetPrivateWindowData(VTE w)
  230.     {
  231.     struct    PrivateWindowData    *pw;
  232.  
  233.     /*
  234.      * First, locate the existing private window data in the list, if any.
  235.      */
  236.     for ( pw = topPrivateWindowData; pw != NULL; pw = pw->next )
  237.     {
  238.         if ( pw->w == w )
  239.             return (pw);        /* Found, return it. */
  240.     }
  241.     /*
  242.      * None found, create a private window data record.
  243.      */
  244.     pw = (void *)NewPtrClear((long)sizeof(*pw));
  245.     pw->w = w;
  246.     pw->next = topPrivateWindowData;
  247.     topPrivateWindowData = pw;
  248.     return (pw);
  249.     }
  250.  
  251. /*
  252.  * Disposes the struct ChangeBar ** record.
  253.  */
  254. static    void
  255. DisposeChangeBars (struct ChangeBar **diff)
  256.     {
  257.     DisposHandle ((Handle)diff);
  258.     }
  259.  
  260. /*
  261.  * Disposes a window's private window data record.
  262.  */
  263. static    void
  264. DisposePrivateWindowData (struct PrivateWindowData *pw)
  265.     {
  266.     if ( pw->diff1Insertions )
  267.         DisposeChangeBars (pw->diff1Insertions);
  268.     DisposePtr ((void *)pw);
  269.     }
  270.  
  271. /*
  272.  * Disposes a window's private window data.  Do this when a window gets closed.
  273.  */
  274. static    void
  275. DeletePrivateWindowData(VTE w)
  276.     {
  277.     struct    PrivateWindowData    **pwLast;
  278.     struct    PrivateWindowData    *pw;
  279.     
  280.     pwLast = &topPrivateWindowData;
  281.     for ( pwLast = &topPrivateWindowData; (pw = (*pwLast)) != NULL; pwLast = &pw->next )
  282.     {
  283.         if ( pw->w == w )
  284.         {
  285.             (*pwLast) = pw->next;
  286.             DisposePrivateWindowData (pw);
  287.             return;
  288.         }
  289.     }
  290.     }
  291.  
  292. /*
  293.  * RemoveWindowFromColumns finds all references to a particular window.
  294.  * This would be necessary if a window gets closed.
  295.  */
  296. static    void
  297. RemoveWindowFromColumns (VTE w)
  298.     {
  299.     struct    PrivateWindowData    *pw;
  300.     int    i;
  301.     
  302.     for ( pw = topPrivateWindowData; pw != NULL; pw = pw->next )
  303.     {
  304.         for ( i = 0; i < 2; i++ )
  305.         {
  306.             if ( pw->columnWindows[i] == w )
  307.                 pw->columnWindows[i] = NULL;
  308.         }
  309.     }
  310.     }
  311.  
  312. /*
  313.  * This sets up a window to have private window data.
  314.  */
  315. static    struct    ChangeBar    **
  316. InitializeWindowDiff (VTE w)
  317.     {
  318.     struct    PrivateWindowData    *pw;
  319.     struct    ChangeBar    newChangeBar;
  320.     
  321.     RemoveWindowFromColumns (w);
  322.     pw = GetPrivateWindowData(w);
  323.     if ( pw->diff1Insertions )
  324.         DisposeChangeBars (pw->diff1Insertions);
  325.     pw->diff1Insertions = (void *)NewHandle(0L);
  326.     return (pw->diff1Insertions);
  327.     }
  328.  
  329. /*
  330.  * This associates the column of one window with another.  A single window can have up
  331.  * to three columns, and each column can be associated with one window.  Thus, a window can
  332.  * be associated with up to three other windows.
  333.  */
  334. static    void
  335. SetColumnWindows (VTE w, VTE wColumn1, VTE wColumn2, VTE wColumn3)
  336.     {
  337.     struct    PrivateWindowData    *pw;
  338.     int    i;
  339.     
  340.     pw = GetPrivateWindowData (w);
  341.     pw->columnWindows[0] = wColumn1;
  342.     pw->columnWindows[1] = wColumn2;
  343.     pw->columnWindows[2] = wColumn3;
  344.     }
  345.  
  346. /*
  347.  * This changes the number of "change bar" columns shown for a window to numColumns.
  348.  */
  349. static    void
  350. SetShowWindowDiff (VTE w, int numColumns)
  351.     {
  352.     struct    PrivateWindowData    *pw;
  353.     GrafPtr    currPort;
  354.     
  355.     pw = GetPrivateWindowData (w);
  356.     if ( pw->diff1Shown != numColumns )
  357.     {
  358.         pw->diff1Shown = numColumns;
  359.         FixScrollBars (w);
  360.     }
  361.     GetPort (&currPort);
  362.     SetPort (w);
  363.     InvalRect (&w->portRect);
  364.     SetPort (currPort);
  365.     }
  366.  
  367. /*
  368.  * SDrawSmallIcon draws an icon at the given point.  It reads the icon from the resource file.
  369.  */
  370. static    void
  371. SDrawSmallIcon    (Point pt, int number, int left, int top, int right, int bottom)
  372.     {
  373.     BitMap    thebits;
  374.     Rect    dest;
  375.     Rect    src;
  376.     static    char    **SICN_Resource;
  377.     
  378.     if ( ! SICN_Resource || ! *SICN_Resource )
  379.     {
  380.         SICN_Resource = GetResource('SICN', 2000);
  381.     }
  382.     
  383.     HNoPurge (SICN_Resource);
  384.     HLock (SICN_Resource);
  385.     
  386.     thebits.baseAddr = (char *)*SICN_Resource + (number << 5);
  387.     thebits.rowBytes = 2;
  388.     thebits.bounds.top = 0;
  389.     thebits.bounds.left = 0;
  390.     thebits.bounds.bottom = 16;
  391.     thebits.bounds.right = 16;
  392.     src.top = top;
  393.     src.left = left;
  394.     src.bottom = bottom;
  395.     src.right = right;
  396.     topLeft(dest) = pt;
  397.     dest.bottom = dest.top + bottom - top;
  398.     dest.right = dest.left + right - left;
  399.     CopyBits    (&thebits, &QDGlobals->thePort->portBits, &src, &dest, srcCopy, NULL);
  400.     HUnlock (SICN_Resource);
  401.     HPurge (SICN_Resource);
  402.     }
  403.  
  404. /*
  405.  * Given a character in the text, this returns the change bar number that this
  406.  * character is inside.  If it is not in a change bar, this routine returns a negative
  407.  * value.
  408.  */
  409. static    long
  410. GetChangeBarNumber    (struct ChangeBar **changeBars, long charno)
  411.     {
  412.     register    struct ChangeBar    *start, *f;
  413.  
  414.     /*
  415.      * If there are no change bars, just return no value.
  416.      */
  417.     if    (!changeBars || !*changeBars)
  418.         return    (-2L);
  419.     start = *changeBars;
  420.     /*
  421.      * Find the change bar that this character is in.
  422.      */
  423.     f = (struct ChangeBar *)((char *)start + GetHandleSize((Handle)changeBars) - sizeof(**changeBars));
  424.     while    (f > start)
  425.         {
  426.         f --;
  427.         if    (f->start <= charno && f->end >= charno)
  428.             return    (f - start);
  429.         }
  430.     return    (-2L);
  431.     }
  432.  
  433. /*
  434.  * ShowChangeBars shows the change bars to the left of a line of text.
  435.  *
  436.  * startl is the character offset of the beginning of the line.  end is the character offset of the
  437.  * end of the line.  changeBars is the change bar record for the current column.  barLeft is the
  438.  * position of the first column.  numColumns is the number of change bar columns.
  439.  */
  440. static    void
  441. ShowChangeBars (VTE w, long startl, long end, struct ChangeBar **folds, Rect *lineRect, int barLeft, int numColumns)
  442.     {
  443.     long    unfolded;
  444.     int    i;
  445.     Point    oPnLoc;
  446.     struct ChangeBar    *unfolds;
  447.     char    state;
  448.     int    column;
  449.     
  450.     state = HGetState((Handle)folds);
  451.     HLock ((Handle)folds);
  452.     
  453.     oPnLoc = w->pnLoc;
  454.     unfolded = GetChangeBarNumber(folds, startl);
  455.     {
  456.         unfolds = (*folds) + unfolded;
  457.         
  458.         for ( ; unfolded >= 0 && unfolds->end >= startl ; --unfolded, --unfolds )
  459.         {
  460.             Rect    foldrect;
  461.             int    i;
  462.     
  463.             for ( column = 0; column < numColumns; column++ )
  464.             {
  465.                 int    isBlack = FALSE;
  466.                 
  467.                 if ( unfolds->whichColumns && ! (unfolds->whichColumns & (cColumn1 << column)) )
  468.                     continue;
  469.                 foldrect = *lineRect;
  470.                 foldrect.left = barLeft + (DIFF_PIXELS * column);
  471.                 foldrect.right = foldrect.left + DIFF_PIXELS - 1;
  472.                 if ( unfolds->end == startl )
  473.                 {
  474.                     if ( unfolds->start < startl )
  475.                         continue;
  476.                     foldrect.top -= 3;
  477.                     foldrect.bottom = foldrect.top + 6;
  478.                     EraseRect (&foldrect);
  479.                     FillOval    (&foldrect, QDGlobals->black);
  480.                     continue;
  481.                 }
  482.                 if ( (unfolds->whichColumns & (cFillBlack1 << column)) )
  483.                 {
  484.                     FillRect    (&foldrect, QDGlobals->black);
  485.                     isBlack = TRUE;
  486.                 }
  487.                 else
  488.                 {
  489.                     MoveTo (foldrect.left, foldrect.top);
  490.                     LineTo (foldrect.left, foldrect.bottom-1);
  491.                     MoveTo (foldrect.right - 1, foldrect.top);
  492.                     LineTo (foldrect.right - 1, foldrect.bottom-1);
  493.                 }
  494.                 unfolds = (*folds) + unfolded;
  495.                 if    (unfolds->start == startl)
  496.                 {
  497.                     i = foldrect.bottom;
  498.                     i -= foldrect.top;
  499.                     if    (i > 15)
  500.                         i = 15;
  501.                     SDrawSmallIcon    (topLeft(foldrect), (isBlack? 2: 0), 0, 0, DIFF_PIXELS - 1, i);
  502.                 }
  503.                 unfolds = (*folds) + unfolded;
  504.                 if    (unfolds->end == end)
  505.                 {
  506.                     foldrect.top += 3;
  507.                     i = 7;
  508.                     i -= foldrect.bottom;
  509.                     i += foldrect.top;
  510.                     if    (i < 0)
  511.                     {
  512.                         i = 0;
  513.                         foldrect.top = foldrect.bottom - 7;
  514.                     }
  515.                     SDrawSmallIcon    (topLeft(foldrect), (isBlack? 3: 1), 0, i, DIFF_PIXELS - 1, 7);
  516.                 }
  517.             }
  518.         }
  519.     }
  520.     w->pnLoc = oPnLoc;
  521.     
  522.     HSetState ((Handle)folds, state);
  523.     }
  524.  
  525. /*
  526.  * DiffShowLeftMarginIcons shows the change bars to the left of a line of text.
  527.  *
  528.  * startl is the character offset of the beginning of the line.  end is the character offset of the
  529.  * end of the line.  lineRect is the rectangle that the line's rectangle.  barPosition is the location
  530.  * of the right side of the change bars.  This routine gets called by QUED whenever a line
  531.  * of text is displayed.  Thus, this routine also call's QUED's original procedure.
  532.  */
  533. static    int
  534. DiffShowLeftMarginIcons (w, startl, end, lineRect, barPosition)
  535.     VTE    w;
  536.     long    startl;
  537.     long    end;
  538.     Rect *lineRect;
  539.     int    barPosition;
  540. {
  541.     int    numColumns;
  542.  
  543.     /* Call QUED's original first. */
  544.     barPosition = (*OriginalShowLeftMarginIcons)(w, startl, end, lineRect, barPosition);
  545.  
  546.     /* Now, draw our change bars. */
  547.     numColumns = GetPrivateWindowData(w)->diff1Shown;
  548.     barPosition -= DIFF_PIXELS * numColumns;
  549.     if ( numColumns )
  550.     {
  551.         ShowChangeBars (w, startl, end, GetPrivateWindowData(w)->diff1Insertions, lineRect, barPosition, numColumns);
  552.     }
  553.     return (barPosition);
  554.     }
  555.  
  556. static    struct    ChangeBar    *
  557. GetScriptChangeBar (VTE otherWindow, int scriptNumber)
  558.     {
  559.     register    struct ChangeBar    *start, *f;
  560.     struct    ChangeBar    **folds;
  561.     
  562.     folds = GetPrivateWindowData (otherWindow)->diff1Insertions;
  563.     
  564.     if    (!folds || !*folds)
  565.         return    (NULL);
  566.     start = *folds;
  567.     f = (struct ChangeBar *)((char *)start + GetHandleSize((Handle)folds) - sizeof(**folds));
  568.     while    (f > start)
  569.         {
  570.         f --;
  571.         if    (f->scriptNumber == scriptNumber )
  572.             return    (f);
  573.         }
  574.     return    (NULL);
  575.     }
  576.  
  577. static    void
  578. SelectScriptNumber (VTE otherWindow, int scriptNumber, long scrollOffset)
  579.     {
  580.     struct    ChangeBar    *f;
  581.     
  582.     f = GetScriptChangeBar(otherWindow, scriptNumber);
  583.     if ( f )
  584.     {
  585.         SetSelect (f->start, f->end, otherWindow);
  586.         SetVScrollValue (otherWindow, scrollOffset + Char2Line (otherWindow, f->start));
  587.     }
  588.     }
  589.  
  590. /*
  591.  * This routine gets called when the user clicks to the left of text.  It determines
  592.  * if the user clicked on one of the change bars, and if so, it handles it appropriately
  593.  * by selecting the associated text in the other windows.
  594.  */
  595. static    int
  596. DiffClickLeftMarginIcons (VTE w, long sel, Point where, int *barPosition)
  597.     {
  598.     struct    PrivateWindowData    *pw;
  599.     int    oBarPosition;
  600.     long    barNo;
  601.     struct    ChangeBar    *theBar;
  602.     VTE    otherWindow;
  603.     int    column;
  604.     
  605.     if ( OriginalClickLeftMarginIcons (w, sel, where, barPosition) )
  606.         return (TRUE);
  607.     pw = GetPrivateWindowData(w);
  608.     oBarPosition = *barPosition;
  609.     *barPosition -= DIFF_PIXELS * pw->diff1Shown;
  610.     if ( where.h < oBarPosition && where.h >= (*barPosition) )
  611.     {
  612.         barNo = GetChangeBarNumber(pw->diff1Insertions, sel);
  613.         if    (barNo < 0)
  614.             return    (FALSE);
  615.         theBar = (*pw->diff1Insertions) + barNo;
  616.         if ( theBar->end == sel && theBar->start != theBar->end )
  617.             return (FALSE);
  618.             
  619.         column = (where.h - (*barPosition)) / DIFF_PIXELS;
  620.         otherWindow = pw->columnWindows[column];
  621.         if ( otherWindow )
  622.         {
  623.             int    scriptNumber = theBar->scriptNumber;
  624.             long    start = theBar->start;
  625.             long    scrollValue = GetVScrollValue (w) - Char2Line (w, start);
  626.             
  627.             for ( column = 0; column < pw->diff1Shown; column++ )
  628.             {
  629.                 otherWindow = pw->columnWindows[column];
  630.                 if ( otherWindow != w )
  631.                     SelectScriptNumber (otherWindow, theBar->scriptNumber, scrollValue);
  632.             }
  633.         }
  634.         return (TRUE);
  635.     }
  636.     return (FALSE);
  637.     }
  638.  
  639.  
  640. /*
  641.  * This returns the width of all the change bar columns for a given window.
  642.  * This is called by QUED.
  643.  */
  644. static    int
  645. DiffGetQuedIconsWidth(VTE w)
  646.     {
  647.     int    add;
  648.     
  649.     add = GetPrivateWindowData(w)->diff1Shown * 10;
  650.     return (add + OriginalGetQuedIconsWidth(w));
  651.     }
  652.  
  653. /*
  654.  * "OffsetMarkers":
  655.  *    It displaces anything which might locate a text position
  656.  *    when characters are inserted/deleted before that
  657.  *    position.  Markers and folds are among those things
  658.  *    that are displaced.
  659.  *
  660.  *    "Loc" is the start of the change.  "ndelete" is the number
  661.  *    of characters to delete.  "length" is the number of
  662.  *    characters to insert.  If "length" is -1, then TRUE
  663.  *    or FALSE is returned, but the markers are NOT displaced.
  664.  *    TRUE is returned if there is a marker or fold
  665.  *    between "loc" and "loc+ndelete".
  666.  *
  667.  */
  668. static    int
  669. DiffOffsetTextMarkers    (w, loc, ndelete, length)
  670.     VTE    w;
  671.     long    loc, ndelete, length;
  672.     {
  673.     register    struct    ChangeBar    *mk;
  674.     long    mloc;
  675.     struct    ChangeBar    *me;
  676.     long    delta;
  677.     struct    ChangeBar    **diff;
  678.  
  679.     if ( OriginalOffsetTextMarkers(w, loc, ndelete, length) )
  680.         return (TRUE);
  681.  
  682.     diff = GetPrivateWindowData(w)->diff1Insertions;
  683.     if ( diff )
  684.     {
  685.         delta = length - ndelete;
  686.         
  687.         mk = *diff;
  688.         me = (struct ChangeBar *)((char *)mk + GetHandleSize((Handle)diff) - (sizeof(**diff)));
  689.         while    (mk < me)
  690.         {
  691.             mloc = mk->start;
  692.             if    (length == -1)
  693.             {
  694.                 if    ( (mloc >= loc && mloc <= loc+ndelete)
  695.                     || (mk->end >= loc && mk->end <= loc+ndelete) )
  696.                     {
  697.                     return    (TRUE);
  698.                     }
  699.             }
  700.             else
  701.             {
  702.                 if    (mloc > loc)
  703.                     {
  704.                     if    (mloc >= loc + ndelete)
  705.                         mloc += delta;
  706.                     else if    (mloc > loc + length)
  707.                         mloc = loc + length;
  708.                     }
  709.                 mk->start = mloc;
  710.                 mloc = mk->end;
  711.                 if    (mloc  > loc)
  712.                     {
  713.                     if    (mloc >= loc + ndelete)
  714.                         mloc += delta;
  715.                     else if    (mloc > loc + length)
  716.                         mloc = loc + length;
  717.                     }
  718.                 mk->end = mloc;
  719.             }
  720.             mk++;
  721.         }
  722.     }
  723.     return    (FALSE);
  724.     }
  725.  
  726. /*
  727.  * Determine if this change should be ignored.  For example, if "Ignore Blank
  728.  * Lines" is set, and ALL of the information in this change is blank lines,
  729.  * return 0.
  730.  *
  731.  * This routine returns a non-zero value if there are any significant differences.
  732.  * If we are comparing a difference of three files, it returns DIFF_ALL, DIFF_1ST, DIFF_2ND, or
  733.  * diff_3RD depending on which file(s) has significant differences from the other(s).
  734.  */
  735. static    struct diff3_block    *
  736. RemoveIgnoredChanges (struct diff3_block *topscript, int nfiles, struct file_data *files)
  737. {
  738.     LONG i;
  739.     int    j;
  740.     int nontrivial;
  741.     int    diff[3];
  742.     struct    diff3_block    **pPrevious = &topscript;
  743.     struct    diff3_block    *script;
  744.     
  745.     if ( ! ignore_blank_lines_flag && ! ignore_regexp )
  746.     {
  747.         return (topscript);    /* I can't eliminate anything. */
  748.     }
  749.  
  750.     for ( script = topscript; script != NULL; script = *pPrevious )
  751.     {
  752.         diff[0] = diff[1] = diff[2] = 0;
  753.         nontrivial = 0;
  754.         for ( j = 0; j < nfiles; j++ )
  755.         {
  756.             for (i = script->ranges[j][START]; i <= script->ranges[j][END]; i++)
  757.             if ((!ignore_blank_lines_flag || files[j].linbuf[i].length > 1)
  758.                 && (!ignore_regexp
  759.                 || 0 > re_search (&ignore_regexp_compiled,
  760.                 files[j].linbuf[i].text,
  761.                 files[j].linbuf[i].length, (LONG)0,
  762.                 files[j].linbuf[i].length, NULL))
  763.                 )
  764.             {
  765.                 nontrivial = 1;
  766.                 diff[j] = 1;
  767.                 break;
  768.             }
  769.         }
  770.         
  771.         /* If all inserted or deleted lines are ignorable,
  772.              tell the caller to ignore this script.  */
  773.         if ( ! nontrivial )
  774.         {
  775.             *pPrevious = script->next;
  776.             free (script);
  777.             continue;
  778.         }
  779.         pPrevious = &script->next;
  780.         if ( nfiles == 2 )
  781.             continue;
  782.         if ( script->correspond != DIFF_ALL )
  783.             continue;
  784.         /* If 3 files, figure out the correct value for "correspond" */
  785.         if ( ! diff[0] && ! diff[1] )
  786.             script->correspond = DIFF_3RD;
  787.         else if ( ! diff[0] && ! diff[2] )
  788.             script->correspond = DIFF_2ND;
  789.         else if ( ! diff[1] && ! diff[2] )
  790.             script->correspond = DIFF_1ST;
  791.     }
  792.     return (topscript);
  793. }
  794.  
  795. /*
  796.  * ShowChangeBars3 puts the change bars to the left of two or three
  797.  * windows, according to the differences found in "script".
  798.  */
  799. static    void
  800. ShowChangeBars3 (struct diff3_block *script, int numDiffs, struct file_data contents[3], VTE w[3])
  801.     {
  802.     struct    ChangeBar    **(diff[3]);
  803.     struct    ChangeBar    startEnd;
  804.     LONG    start, end;
  805.     int    i;
  806.     int    scriptNumber = 0;
  807.     int    correspond;
  808.  
  809.     bzero (&startEnd, sizeof(startEnd));
  810.     for ( i = 0; i < numDiffs; i++ )
  811.     {
  812.         diff[i] = InitializeWindowDiff(w[i]);
  813.     }
  814.     for ( ; script != NULL; (script = script->link), scriptNumber++ )
  815.     {
  816.         struct file_data *contents0 = &contents[0];
  817.         
  818.         correspond = script->correspond;
  819.         for ( i = 0; i < numDiffs; i++, contents0++ )
  820.         {
  821.             start = script->ranges[i][START];
  822.             end = script->ranges[i][END] + 1;
  823.  
  824.             startEnd.whichColumns = cColumn1;        /* Assume this represents a "change" */
  825.             if ( numDiffs == 2 )
  826.             {
  827.                 LONG    startText, endText;
  828.                 
  829.                 startText = script->ranges[1 - i][START];
  830.                 endText = script->ranges[1 - i][END] + 1;
  831.                 if ( startText == endText )
  832.                     startEnd.whichColumns |= cFillBlack1;        /* This means this represents an "insert". */
  833.             }
  834.             else
  835.             {
  836.                 int    other;
  837.                 LONG    startText, endText;
  838.                 
  839.                 if ( correspond == DIFF_ALL || i == correspond - DIFF_1ST )
  840.                 {
  841.                     /* Put into both columns. */
  842.                     startEnd.whichColumns = cColumn1 | cColumn2;
  843.                 }
  844.                 else
  845.                 {
  846.                     if ( (i + 2) % 3 == correspond - DIFF_1ST )
  847.                         startEnd.whichColumns = cColumn2;
  848.                 }
  849.                 other = (i + 1) % 3;
  850.                 startText = script->ranges[other][START];
  851.                 endText = script->ranges[other][END] + 1;
  852.                 if ( startText == endText )
  853.                     startEnd.whichColumns |= cFillBlack1;
  854.                 other = (i + 2) % 3;
  855.                 startText = script->ranges[other][START];
  856.                 endText = script->ranges[other][END] + 1;
  857.                 if ( startText == endText )
  858.                     startEnd.whichColumns |= cFillBlack2;
  859.             }
  860.             startEnd.start = contents0->linbuf[start].text - contents0->buffer;
  861.             startEnd.end = contents0->linbuf[end - 1].text + contents0->linbuf[end - 1].length - contents0->buffer;
  862.             startEnd.scriptNumber = scriptNumber;
  863.             PtrAndHand (&startEnd, (Handle)diff[i], (long)sizeof(startEnd));
  864.         }
  865.     }
  866.     startEnd.start = startEnd.end = 0x7FFFFFFF;
  867.     for ( i = 0; i < numDiffs; i++ )
  868.     {
  869.         startEnd.scriptNumber = scriptNumber;
  870.         PtrAndHand (&startEnd, (Handle)diff[i], (long)sizeof(startEnd));
  871.         SetShowWindowDiff (w[i], numDiffs - 1);
  872.     }
  873.     }
  874.  
  875. /*
  876.  * Merge3FilesFromBase merges w[1] and w[2] into w[0] and puts the result into wMerge (which
  877.  * may be the same as w[0]).  It also puts change bars to the left of these windows.  "script" is
  878.  * the diff script.
  879.  */
  880. static    void
  881. Merge3FilesFromBase (struct diff3_block *script, struct file_data contents[3], VTE wMerge, int showChangeBarsOnly, VTE w[3])
  882.     {
  883.     char    *startText;
  884.     char    *endText;
  885.     int    i;
  886.     int    conflict;
  887.     Handle    theChange;
  888.     char    str[256];
  889.     int    firstFile, lastFile;
  890.     long    mergeOffset = 0;
  891.     struct    ChangeBar    **diff;
  892.     struct    ChangeBar    startEnd;
  893.     int    scriptNumber = 0;
  894.     int    correspond;
  895.     
  896.     bzero (&startEnd, sizeof(startEnd));
  897.     if ( showChangeBarsOnly )
  898.     {
  899.         diff = InitializeWindowDiff(wMerge);
  900.     }
  901.     else
  902.     {
  903.         SetupChanges ("\pMerge 3 Files");
  904.     }
  905.     for ( ; script != NULL; (script = script->link), scriptNumber++ )
  906.     {
  907.         correspond = script->correspond;
  908.         if ( ! showChangeBarsOnly )
  909.             theChange = NewHandle(0L);
  910.         firstFile = lastFile = 2;
  911.         conflict = FALSE;
  912.         /* The way we merge the files depends on which ones are different than the others. */
  913.         switch ( correspond )
  914.         {
  915.         case DIFF_ALL:
  916.             /* Both files 2 and 3 were changed in different ways wrt file 1.  Output
  917.                the results of all three. */
  918.             conflict = TRUE;
  919.             firstFile = 0;
  920.             break;
  921.         case DIFF_2ND:
  922.             firstFile = lastFile = 1;
  923.             break;
  924.         }
  925.         for ( i = firstFile; i <= lastFile; i++ )
  926.         {
  927.             if ( conflict )
  928.             {
  929.                 long    size;
  930.                 
  931.                 Qued_sprintf (str, i? (i == 1? ">>>>>>> %s(%d)\r": "<<<<<<< %s(%d)\r"): "======= %s(%d)\r", contents[i].name, i);
  932.                 size = strlen(str);
  933.                 if ( ! showChangeBarsOnly )
  934.                     PtrAndHand (str, theChange, size);
  935.                 mergeOffset += size;
  936.             }
  937.             startText = contents[i].linbuf[script->ranges[i][START]].text;
  938.             endText = contents[i].linbuf[script->ranges[i][END]].text + contents[i].linbuf[script->ranges[i][END]].length;
  939.             if ( ! showChangeBarsOnly )
  940.                 PtrAndHand (startText, theChange, (long)endText - (long)startText);
  941.             if ( showChangeBarsOnly )
  942.             {
  943.                 startEnd.whichColumns = (cColumn1 << i);
  944.                 if ( correspond == DIFF_1ST )
  945.                     startEnd.whichColumns = (cColumn2 | cColumn3);
  946.                 if ( ! conflict && script->ranges[0][START] != script->ranges[0][END] + 1 )
  947.                 {
  948.                     char    *startText, *endText;
  949.                     
  950.                     startText = contents[0].linbuf[script->ranges[0][START]].text;
  951.                     endText = contents[0].linbuf[script->ranges[0][END]].text + contents[0].linbuf[script->ranges[0][END]].length;
  952.                     startEnd.whichColumns |= (cFillBlack1 << i);
  953.                     if ( correspond == DIFF_1ST )
  954.                         startEnd.whichColumns |= (cFillBlack2 | cFillBlack3);
  955.                 }
  956.                 startEnd.start = contents[0].linbuf[script->ranges[0][START]].text - contents[0].buffer + mergeOffset;
  957.                 startEnd.end = startEnd.start + endText - startText;
  958.                 startEnd.scriptNumber = scriptNumber;
  959.                 PtrAndHand (&startEnd, (Handle)diff, (long)sizeof(startEnd));
  960.             }
  961.             mergeOffset += (long)endText - (long)startText;
  962.         }
  963.         if ( conflict )
  964.         {
  965.             long    size;
  966.             
  967.             Qued_sprintf (str, "=======\r");
  968.             size = strlen(str);
  969.             if ( ! showChangeBarsOnly )
  970.                 PtrAndHand (str, theChange, size);
  971.             mergeOffset += size;
  972.         }
  973.         startText = contents[0].linbuf[script->ranges[0][START]].text;
  974.         endText = contents[0].linbuf[script->ranges[0][END]].text + contents[0].linbuf[script->ranges[0][END]].length;
  975.         mergeOffset -= endText - startText;
  976.         if ( ! showChangeBarsOnly )
  977.         {
  978.             AddChanges (wMerge, startText - contents[0].buffer, endText - startText, -1L, (char *)theChange);
  979.         }
  980.     }
  981.     if ( showChangeBarsOnly )
  982.     {
  983.         startEnd.start = startEnd.end = 0x7FFFFFFF;
  984.         startEnd.scriptNumber = scriptNumber;
  985.         PtrAndHand (&startEnd, (Handle)diff, (long)sizeof(startEnd));
  986.         SetShowWindowDiff (wMerge, 3);
  987.     }
  988.     }
  989.  
  990. /*
  991.  * This coelesces the contents of two or three files (depending on the value of numDiffs), according
  992.  * to the diff script placed in "script".  The
  993.  * files' contents are in w[0], w[1], and possibly w[2].  The result should be put into wMerge,
  994.  * which may be the same as w[0].
  995.  */
  996. static    void
  997. MergeFiles (struct diff3_block *script, int numDiffs, struct file_data contents[3], VTE wMerge, int showChangeBarsOnly, VTE w[3])
  998.     {
  999.     char    *startText;
  1000.     char    *endText;
  1001.     int    i;
  1002.     struct    ChangeBar    startEndx;
  1003.     struct    ChangeBar    startEnd;
  1004.     long    mergeOffset = 0;
  1005.     struct    ChangeBar    **diff;
  1006.     LONG    end1change;
  1007.     int    scriptNumber = 0;
  1008.     int    correspond;
  1009.     
  1010.     bzero (&startEndx, sizeof(startEndx));
  1011.     bzero (&startEnd, sizeof(startEnd));
  1012.     if ( showChangeBarsOnly )
  1013.     {
  1014.         diff = InitializeWindowDiff(wMerge);
  1015.     }
  1016.     else
  1017.         SetupChanges ("\pCoelesce Files");
  1018.     for ( ; script != NULL; (script = script->link), scriptNumber++ )
  1019.     {
  1020.         correspond = script->correspond;
  1021.         startEndx.start = contents[0].linbuf[script->ranges[0][START]].text - contents[0].buffer + mergeOffset;
  1022.         end1change = contents[0].linbuf[script->ranges[0][END]].text + contents[0].linbuf[script->ranges[0][END]].length - contents[0].buffer;
  1023.         startEndx.end = end1change + mergeOffset;
  1024.         if ( showChangeBarsOnly )
  1025.         {
  1026.             if ( startEndx.end > startEndx.start )
  1027.             {
  1028.                 startEndx.whichColumns = cColumn1;
  1029.                 if ( numDiffs == 3 )
  1030.                 {
  1031.                     if ( correspond == DIFF_2ND )
  1032.                         startEndx.whichColumns = (cColumn1 | cColumn3);
  1033.                     if ( correspond == DIFF_3RD )
  1034.                         startEndx.whichColumns = (cColumn1 | cColumn2);
  1035.                 }
  1036.                 startEndx.scriptNumber = scriptNumber;
  1037.                 PtrAndHand (&startEndx, (Handle)diff, (long)sizeof(startEndx));
  1038.             }
  1039.         }
  1040.         for ( i = 1; i < numDiffs; i++ )
  1041.         {
  1042.             if ( numDiffs == 3 )
  1043.             {
  1044.                 if ( i == 2 && ( correspond == DIFF_1ST || correspond == DIFF_2ND ) )
  1045.                     continue;    /* Ignore this case. */
  1046.                 if ( i == 1 && ( correspond == DIFF_3RD ) )
  1047.                     continue;    /* Ignore this case. */
  1048.             }
  1049.             startText = contents[i].linbuf[script->ranges[i][START]].text;
  1050.             endText = contents[i].linbuf[script->ranges[i][END]].text + contents[i].linbuf[script->ranges[i][END]].length;
  1051.             if ( endText != startText )
  1052.             {
  1053.                 if ( showChangeBarsOnly )
  1054.                 {
  1055.                     startEnd.start = startEndx.end;
  1056.                     startEnd.end = startEnd.start + endText - startText;
  1057.                     startEnd.whichColumns = (cColumn1 << i);
  1058.                     if ( numDiffs == 3 && correspond == DIFF_1ST )
  1059.                         startEnd.whichColumns = (cColumn2 | cColumn3);
  1060.                     startEnd.scriptNumber = scriptNumber;
  1061.                     PtrAndHand (&startEnd, (Handle)diff, (long)sizeof(startEnd));
  1062.                 }
  1063.                 else if ( startText != endText )
  1064.                 {
  1065.                     AddChanges (wMerge, end1change, 0L, endText - startText, startText);
  1066.                 }
  1067.                 mergeOffset += endText - startText;
  1068.                 startEndx.end += endText - startText;
  1069.             }
  1070.         }
  1071.     }
  1072.     if ( showChangeBarsOnly )
  1073.     {
  1074.         startEnd.start = startEnd.end = 0x7FFFFFFF;
  1075.         startEnd.scriptNumber = scriptNumber;
  1076.         PtrAndHand (&startEnd, (Handle)diff, (long)sizeof(startEnd));
  1077.         SetShowWindowDiff (wMerge, numDiffs);
  1078.     }
  1079.     }
  1080.  
  1081. /*
  1082.  * This executes the menu command "2-File Differences" or "3-File Differences" depending
  1083.  * on the flag doDiff3.
  1084.  */
  1085. static    void
  1086. DoDiffMenu (Boolean doDiff3)
  1087.     {
  1088.     struct    file_data    filevec[4];
  1089.     struct    file_data    contents[3];
  1090.     WindowPtr    wNew = NULL;
  1091.     Handle    firstText, secondText;
  1092.     struct    change    *script;
  1093.     int    printSeparate = TRUE;
  1094.     int    mergeFiles = FALSE;
  1095.     int    mergeFromBase = FALSE;
  1096.     long    size;
  1097.     int    executeFlag = FALSE;
  1098.     VTE    wArray[3];
  1099.     VTE    wMerge = NULL;
  1100.     int    mapping[3] = { 0, 1, 2 };
  1101.     char    fileNames[3][256];
  1102.     FILE    theOutputFile;
  1103.     
  1104.     /* This prevents calls to "putc" from screwing up. */
  1105.     /* Make both "outfile" and "stdout" direct output to our new window! */
  1106.     bzero (&theOutputFile, sizeof(theOutputFile));
  1107.     outfile = &theOutputFile;
  1108.     
  1109.     /*
  1110.      * This sets the various "globals" used by the DIFF program.
  1111.      */
  1112.     {
  1113.         /*
  1114.          * Initialize the global flags, and then set them up according to our
  1115.          * last chosen values from the Diff Options... dialog.
  1116.          */
  1117.         ignore_space_change_flag = (diffOptions.ignoreMultipleBlanks != 0);
  1118.         ignore_blank_lines_flag = (diffOptions.ignoreBlankLines != 0);
  1119.         length_varies = (ignore_space_change_flag || ignore_all_space_flag);
  1120.         ignore_all_space_flag = (diffOptions.ignoreAllBlanks != 0);
  1121.         ignore_case_flag = (diffOptions.ignoreCase != 0);
  1122.         heuristic = (diffOptions.fastCompare != 0);
  1123.         paginate_flag = TRUE;
  1124.         always_text_flag = TRUE;
  1125.         function_regexp = NULL;
  1126.         ignore_regexp = NULL;
  1127.         ignore_regexp_compiled.fastmap = NULL;
  1128.         function_regexp_compiled.fastmap = NULL;
  1129.         bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
  1130.         bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
  1131.         if ( diffOptions.ignoreLinesContaining )
  1132.         {
  1133.             char *val;
  1134.             ignore_regexp = diffOptions.linesContaining;
  1135.             val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
  1136.                     &ignore_regexp_compiled);
  1137.             if (val != 0)
  1138.                 goto done;
  1139.                 /* error ("-I option: ", val); */
  1140.             ignore_regexp_compiled.fastmap = (char *) xmalloc ((size_t)256);
  1141.         }
  1142.         output_style = 0;
  1143.         context = 0;
  1144.         switch (doDiff3? diffOptions.presentCompareResult3 + 100: diffOptions.presentCompareResult2)
  1145.         {
  1146.         case    cShowChangeBars2:
  1147.         case    cShowChangeBars3 + 100:
  1148.             printSeparate = FALSE;
  1149.             break;
  1150.             
  1151.         case cMerge3 + 100:
  1152.             mergeFromBase = TRUE;
  1153.             /* Float on through */
  1154.             
  1155.         case cIfdef2:
  1156.             if ( diffOptions.ifdef[0] )
  1157.             {
  1158.                 output_style = OUTPUT_IFDEF;
  1159.                 ifdef_string = diffOptions.ifdef;
  1160.                 break;
  1161.             }
  1162.             /* Otherwise, float on through and create a composite window. */
  1163.             
  1164.         case    cComposite2:
  1165.         case    cComposite3 + 100:
  1166.             printSeparate = FALSE;
  1167.             mergeFiles = TRUE;
  1168.             break;
  1169.         
  1170.         case cUnified2:
  1171.             output_style = OUTPUT_UNIFIED;
  1172.             context = 0;
  1173.             goto    unified;
  1174.             
  1175.         case    cUNIX2:
  1176.         case    cUNIX3 + 100:
  1177.             output_style = OUTPUT_NORMAL;
  1178.             if ( diffOptions.isContext || diffOptions.linePreceedingIs )
  1179.             {
  1180.                 output_style = OUTPUT_CONTEXT;
  1181.         unified:
  1182.                 if ( diffOptions.isContext )
  1183.                     context = diffOptions.contextLines;
  1184.                 if ( diffOptions.linePreceedingIs )
  1185.                 {
  1186.                     char *val;
  1187.                     
  1188.                     function_regexp = diffOptions.linePreceeding;
  1189.                     val = re_compile_pattern (function_regexp, strlen (function_regexp),
  1190.                             &function_regexp_compiled);
  1191.                     if (val != 0)
  1192.                         goto done;
  1193.                         /* error ("-F option: ", val); */
  1194.                     function_regexp_compiled.fastmap = (char *) xmalloc ((size_t)256);
  1195.                 }
  1196.             }
  1197.             break;
  1198.         case    cED2:
  1199.             output_style = OUTPUT_ED;
  1200.             break;
  1201.             
  1202.         case    cForwardED2:
  1203.             output_style = OUTPUT_FORWARD_ED;
  1204.             break;
  1205.             
  1206.         case    cRCS2:
  1207.             output_style = OUTPUT_RCS;
  1208.             break;
  1209.         }
  1210.     }
  1211.  
  1212.     /*
  1213.      * Initialize stdout.
  1214.      */
  1215.     outFileHandle = NULL;    /* Stdout will append to this handle. */
  1216.     {
  1217.         int    file_differs;
  1218.  
  1219.         /*
  1220.          * Get the windows to operate on.
  1221.          */
  1222.         wArray[0] = NextFileWindow(NULL);
  1223.         wArray[1] = NextFileWindow(wArray[0]);
  1224.         wArray[2] = NextFileWindow(wArray[1]);
  1225.  
  1226.         /*
  1227.          * If there aren't enough windows, just exit.
  1228.          */
  1229.         if ( ! wArray[0] || ! wArray[1] || (doDiff3 && ! wArray[2]) )
  1230.             goto done;
  1231.         
  1232.         wMerge = wArray[0];
  1233.  
  1234.         /*
  1235.          * Create a new window if they specified.
  1236.          */
  1237.         if ( printSeparate || ( ! diffOptions.replaceTopWindow && mergeFiles ) )
  1238.         {
  1239.             wNew = NewFile();
  1240.             
  1241.             if ( ! wNew )
  1242.                 goto done;
  1243.         }
  1244.         
  1245.         firstText = GetWindowText(wArray[0]);
  1246.         
  1247.         outFileHandle = GetWindowText(wNew);
  1248.         SetHandleSize (outFileHandle, 0L);
  1249.         if ( ! diffOptions.replaceTopWindow && mergeFiles )
  1250.         {
  1251.             long    size;
  1252.             
  1253.             SetHandleSize (outFileHandle, size = GetHandleSize(firstText));
  1254.             if ( MemErr )
  1255.             {
  1256.                 KillTextWindow (wNew);
  1257.                 goto done;
  1258.             }
  1259.             BlockMove (*firstText, *outFileHandle, size);
  1260.             firstText = outFileHandle;
  1261.             outFileHandle = NULL;
  1262.             wMerge = wNew;
  1263.         }
  1264.         
  1265.         secondText = GetWindowText(wArray[1]);
  1266.         PtrAndHand ("\r\r", firstText, 2L);
  1267.         PtrAndHand ("\r\r", secondText, 2L);
  1268.         
  1269.         line_end_char = NEWLINE;
  1270.         
  1271.         bzero (&filevec, sizeof(filevec));
  1272.         bzero (&contents, sizeof(filevec));
  1273.         
  1274.         contents[0].buffered_chars = GetHandleSize(firstText) - 1;
  1275.         contents[1].buffered_chars = GetHandleSize(secondText) - 1;
  1276.         
  1277.         GetWTitle (wArray[0], (unsigned char *)fileNames[0]);
  1278.         PtoCstr ((void *)fileNames[0]);
  1279.         contents[0].name = fileNames[0];
  1280.         
  1281.         GetWTitle (wArray[1], (unsigned char *)fileNames[1]);
  1282.         PtoCstr ((void *)fileNames[1]);
  1283.         contents[1].name = fileNames[1];
  1284.         
  1285.         MoveHHi (firstText);
  1286.         MoveHHi (secondText);
  1287.         HLock (secondText);
  1288.         MoveHHi (firstText);
  1289.         HLock (firstText);
  1290.         contents[0].buffer = *firstText;
  1291.         contents[1].buffer = *secondText;
  1292.         
  1293.         filevec[0] = contents[0];
  1294.         filevec[1] = contents[1];
  1295.         
  1296.         script = diff_2_files_no_print (&filevec[0], &file_differs);
  1297.         
  1298.         contents[0] = filevec[0];
  1299.         contents[1] = filevec[1];
  1300.         
  1301.         if ( doDiff3 )
  1302.         {
  1303.             Handle    thirdText;
  1304.             struct    change    *script2;
  1305.             struct diff3_block *diff;
  1306.             
  1307.             thirdText = GetWindowText(wArray[2]);
  1308.             PtrAndHand ("\r\r", thirdText, 2L);
  1309.             MoveHHi (thirdText);
  1310.             HLock (thirdText);
  1311.             contents[2].buffered_chars = GetHandleSize(thirdText) - 1;
  1312.             contents[2].buffer = *thirdText;
  1313.             
  1314.             GetWTitle (wArray[2], (unsigned char *)fileNames[2]);
  1315.             PtoCstr ((void *)fileNames[2]);
  1316.             contents[2].name = fileNames[2];
  1317.             
  1318.             filevec[2] = contents[0];
  1319.             filevec[3] = contents[2];
  1320.             script2 = diff_2_files_no_print (&filevec[2], &file_differs);
  1321.             
  1322.             contents[0] = filevec[2];
  1323.             contents[2] = filevec[3];
  1324.         
  1325.             BlockMove (contents, diff3_file_data, (long)sizeof(contents));
  1326.             
  1327.             diff = make_3way_diff (script, script2);
  1328.             diff = RemoveIgnoredChanges (diff, 3, contents);
  1329.             script = NULL;    /* So the later call to dispose_script does nothing */
  1330.             if ( diff )
  1331.             {
  1332.                 if ( diffOptions.showChangeBars )
  1333.                 {
  1334.                     ShowChangeBars3 (diff, 3, contents, wArray);
  1335.                     SetColumnWindows (wArray[0], wArray[1], wArray[2], NULL);
  1336.                     SetColumnWindows (wArray[1], wArray[2], wArray[0], NULL);
  1337.                     SetColumnWindows (wArray[2], wArray[0], wArray[1], NULL);
  1338.                 }
  1339.                     
  1340.                 if ( printSeparate )
  1341.                 {
  1342.                     output_diff3 ( NULL, diff, mapping, mapping);
  1343.                 }
  1344.                 else if ( mergeFiles )
  1345.                 {
  1346.                     if ( mergeFromBase )
  1347.                     {
  1348.                         Merge3FilesFromBase (diff, contents, wMerge, FALSE, wArray);
  1349.                     }
  1350.                     else
  1351.                     {
  1352.                         MergeFiles (diff, 3, contents, wMerge, FALSE, wArray);
  1353.                     }
  1354.                     if ( diffOptions.showChangeBars )
  1355.                         SetColumnWindows (wMerge, wArray[0], wArray[1], wArray[2]);
  1356.                     executeFlag = TRUE;
  1357.                 }
  1358.                 else if ( ! diffOptions.showChangeBars )
  1359.                 {
  1360.                     ShowChangeBars3 (diff, 3, contents, wArray);
  1361.                     SetColumnWindows (wArray[0], wArray[1], wArray[2], NULL);
  1362.                     SetColumnWindows (wArray[1], wArray[2], wArray[0], NULL);
  1363.                     SetColumnWindows (wArray[2], wArray[0], wArray[1], NULL);
  1364.                 }
  1365.             }
  1366.             HUnlock (thirdText);
  1367.             SetHandleSize (thirdText, GetHandleSize(thirdText) - 2);
  1368.             script = (struct change *)diff;
  1369.         }
  1370.         else
  1371.         {
  1372.                 
  1373.             if ( printSeparate )
  1374.             {
  1375.                 print_results (filevec, script, 0);
  1376.                 script = (struct change *)RemoveIgnoredChanges ((struct diff3_block *)script, 2, contents);
  1377.                 if ( diffOptions.showChangeBars )
  1378.                 {
  1379.                     ShowChangeBars3 ((struct diff3_block *)script, 2, contents, wArray);
  1380.                     SetColumnWindows (wArray[0], wArray[1], NULL, NULL);
  1381.                     SetColumnWindows (wArray[1], wArray[0], NULL, NULL);
  1382.                 }
  1383.             }
  1384.             else
  1385.             {
  1386.                 script = (struct change *)RemoveIgnoredChanges ((struct diff3_block *)script, 2, contents);
  1387.                 if ( diffOptions.showChangeBars )
  1388.                 {
  1389.                     ShowChangeBars3 ((struct diff3_block *)script, 2, contents, wArray);
  1390.                     SetColumnWindows (wArray[0], wArray[1], NULL, NULL);
  1391.                     SetColumnWindows (wArray[1], wArray[0], NULL, NULL);
  1392.                 }
  1393.                 if ( mergeFiles )
  1394.                 {
  1395.                     MergeFiles ((struct diff3_block *)script, 2, contents, wMerge, FALSE, wArray);
  1396.                     if ( diffOptions.showChangeBars )
  1397.                         SetColumnWindows (wMerge, wArray[0], wArray[1], NULL);
  1398.                     executeFlag = TRUE;
  1399.                 }
  1400.                 else if ( ! diffOptions.showChangeBars )
  1401.                 {
  1402.                     ShowChangeBars3 ((struct diff3_block *)script, 2, contents, wArray);
  1403.                     SetColumnWindows (wArray[0], wArray[1], NULL, NULL);
  1404.                     SetColumnWindows (wArray[1], wArray[0], NULL, NULL);
  1405.                 }
  1406.             }
  1407.         }
  1408.         if ( ! executeFlag )    /* I will need this afterwards. */
  1409.         {
  1410.             dispose_script (script);
  1411.             {
  1412.                 int    i;
  1413.                 
  1414.                 for (i = 0; i <= 2; ++i)
  1415.                 {
  1416.                     if ( contents[i].linbuf )
  1417.                         free (contents[i].linbuf);
  1418.                 }
  1419.             }
  1420.         }
  1421.         HUnlock (firstText);
  1422.         HUnlock (secondText);
  1423.         SetHandleSize (firstText, GetHandleSize(firstText) - 2);
  1424.         SetHandleSize (secondText, GetHandleSize(secondText) - 2);
  1425.         if ( wNew )
  1426.             RecalcWindow (wNew);
  1427.         if ( executeFlag )
  1428.         {
  1429.             if ( ExecuteTextChanges () )
  1430.             {
  1431.                 if ( mergeFromBase )
  1432.                 {
  1433.                     Merge3FilesFromBase ((struct diff3_block *)script, contents, wMerge, TRUE, wArray);
  1434.                 }
  1435.                 else
  1436.                 {
  1437.                     MergeFiles ((struct diff3_block *)script, doDiff3? 3: 2, contents, wMerge, TRUE, wArray);
  1438.                 }
  1439.                 if ( diffOptions.showChangeBars )
  1440.                     SetColumnWindows(wMerge, wArray[0], wArray[1], wArray[2]);
  1441.             }
  1442.             dispose_script (script);
  1443.             {
  1444.                 int    i;
  1445.                 
  1446.                 for (i = 0; i <= 2; ++i)
  1447.                 {
  1448.                     if ( contents[i].linbuf )
  1449.                         free (contents[i].linbuf);
  1450.                 }
  1451.             }
  1452.         }
  1453.     }
  1454. done:
  1455.     free (ignore_regexp_compiled.fastmap);
  1456.     ignore_regexp_compiled.fastmap = NULL;
  1457.     free (ignore_regexp_compiled.buffer);
  1458.     ignore_regexp_compiled.buffer = NULL;
  1459.     free (function_regexp_compiled.fastmap);
  1460.     function_regexp_compiled.fastmap = NULL;
  1461.     free (function_regexp_compiled.buffer);
  1462.     function_regexp_compiled.buffer = NULL;
  1463.     if ( allocatedBlocks != 0 )
  1464.     {
  1465. #ifdef    DEBUGGING
  1466.         DebugStr ("\pallocatedBlocks != 0");
  1467. #endif
  1468.         allocatedBlocks = 0;
  1469.     }
  1470.     }
  1471.  
  1472. static    void
  1473. DoDiffMenu3 (MenuHandle mh, int theItem)
  1474.     {
  1475.     DoDiffMenu (TRUE);
  1476.     }
  1477.  
  1478. static    void
  1479. DoDiffMenu2 (MenuHandle mh, int theItem)
  1480.     {
  1481.     DoDiffMenu (FALSE);
  1482.     }
  1483.  
  1484. static    void
  1485. ShowHideItems (VTE w, int firstItem, int lastItem, int show)
  1486.     {
  1487.     for ( ; firstItem <= lastItem; firstItem++ )
  1488.     {
  1489.         if ( show )
  1490.             ShowDItem (w, firstItem);
  1491.         else
  1492.             HideDItem (w, firstItem);
  1493.     }
  1494.     }
  1495.  
  1496. /*
  1497.  * GetItemControl:
  1498.  *    Get the control Handle for a particular Item number in a dialog.
  1499.  */
  1500. static    ControlHandle
  1501. GetItemControl    (dialog, itemno)
  1502.     VTE    dialog;
  1503.     int    itemno;
  1504.     {
  1505.     Rect    box;
  1506.     Handle    Item;
  1507.     short    type;
  1508.  
  1509.     GetDItem(dialog, itemno, &type, &Item, &box);
  1510.     return    ((ControlHandle)Item);
  1511.     }
  1512.  
  1513. /*
  1514.  * GetItemValue:
  1515.  *    Get the value of a control in the dialog box.
  1516.  */
  1517. static    int
  1518. GetItemValue    (dialog, itemno)
  1519.     VTE    dialog;
  1520.     int    itemno;
  1521.     {
  1522.     return    (GetCtlValue(GetItemControl    (dialog, itemno)));
  1523.     }
  1524.  
  1525. /*
  1526.  * Make sure that the correct items are hidden/shown depending upon the currently
  1527.  * chosen settings.
  1528.  */
  1529. static    void
  1530. ValidateDialog (VTE w, int itemHit)
  1531.     {
  1532.     int    value2, value3;
  1533.     
  1534.     value2 = GetItemValue (w, DITEM_TWOFILES);
  1535.     value3 = GetItemValue (w, DITEM_THREEFILES);
  1536.     ShowHideItems (w, DITEM_FIRSTWINDOW, DITEM_LASTWINDOW, value2 == cComposite2 || value3 == cComposite3 || value3 == cMerge3 );
  1537.     ShowHideItems (w, DITEM_FIRSTUNIX, DITEM_LASTUNIX, value2 == cUNIX2 || value2 == cUnified2 );
  1538.     ShowHideItems (w, DITEM_FIRSTSHOWCHANGEBARS, DITEM_LASTSHOWCHANGEBARS, value2 != cShowChangeBars2 || value3 != cShowChangeBars3 );
  1539.     ShowHideItems (w, DITEM_FIRSTIFDEF, DITEM_LASTIFDEF, value2 == cIfdef2 );
  1540.     }
  1541.  
  1542. /*
  1543.  * This executes the "Differences Options..." command on the menu.  It displays the options
  1544.  * dialog and changes the settings.
  1545.  */
  1546. static    void
  1547. DoDiffOptions (MenuHandle mh, int theItem, void *valuePtr, long mainFunc)
  1548.     {
  1549.     WindowPtr    d;
  1550.     short    itemHit;
  1551.     short    type;
  1552.     Handle    h;
  1553.     Rect    box;
  1554.     
  1555.     diffOptions.ifdefLength = diffOptions.linePreceedingLength = diffOptions.linesContainingLength = -256;
  1556.     mh = GetMenu (2000);
  1557.     (*mh)->menuID = 2000;
  1558.     InsertMenu (mh, -1);
  1559.     d = CreateUserDialog (2000, NULL, KillUserDialog);
  1560.     SwapStructureWithDialog (d, TRUE, &diffOptions, (long)sizeof(diffOptions), 0);
  1561.     
  1562.     ValidateDialog (d, itemHit);
  1563.     ShowWindow    (d);
  1564.     
  1565.     do
  1566.         {
  1567.         ModalDialog    (FilterDialogEvent, &itemHit);
  1568.         GetDItem (d, itemHit, &type, &h, &box);
  1569.         DialogButton (d, itemHit);
  1570.         ValidateDialog (d, itemHit);
  1571.         }    while    (type != ctrlItem + btnCtrl);
  1572.         
  1573.     if ( itemHit != 2 )
  1574.         SwapStructureWithDialog (d, FALSE, &diffOptions, (long)sizeof(diffOptions), 0);
  1575.     KillUserDialog (d);
  1576.     DeleteMenu (2000);
  1577.     }
  1578.  
  1579. /*
  1580.  * This is execute when the preferences are read in.  This gives the Diff module
  1581.  * a chance to read in its own preferences.
  1582.  */
  1583. static    void
  1584. DiffReadPreferences(void)
  1585.     {
  1586.     struct    DiffOptions    **defaultStffHndl;
  1587.     
  1588.     defaultStffHndl = (struct DiffOptions **) Get1Resource ('DIFF', 256);
  1589.     if (defaultStffHndl && GetHandleSize((Handle)defaultStffHndl) == sizeof(struct DiffOptions))
  1590.         {
  1591.         diffOptions = **defaultStffHndl;
  1592.         ReleaseResource ((Handle)defaultStffHndl);
  1593.         }
  1594.     (*OriginalReadPreferences) ();
  1595.     }
  1596.  
  1597. /*
  1598.  * This gets execute when the user chooses Save Preferences... .
  1599.  */
  1600. static    void
  1601. DiffSavePreferences(void)
  1602.     {
  1603.     struct    DiffOptions    **defs;
  1604.     int    theError = 0;
  1605.     
  1606.     if    (!(defs = (struct DiffOptions **)Get1Resource('DIFF', 256)))
  1607.     {
  1608.         defs = (void *)NewHandle(0L);
  1609.         AddResource ((Handle)defs, 'DIFF', 256, "\p");
  1610.         theError = ResErr;
  1611.     }
  1612.     PtrToXHand (&diffOptions, (Handle)defs, (long)sizeof(diffOptions));
  1613.     ResErr = theError;
  1614.     if ( ! ResErr )
  1615.         ChangedResource    ((Handle)defs);
  1616.     if    (!ResErr)
  1617.         WriteResource    ((Handle)defs);
  1618.     /* if    (ResErr)
  1619.         Warn    (CStrings[STR_BADSAVEDEFS],  ResErr); */
  1620.     ReleaseResource    ((Handle)defs);
  1621.     (*OriginalSavePreferences) ();
  1622.     }
  1623.  
  1624. /*
  1625.  * This gets executed whenever the user closes a document window.  This way the
  1626.  * Diff module can dispose of its own stuff as well.
  1627.  */
  1628. static    void
  1629. DiffKillTextWindow (VTE w)
  1630.     {
  1631.     RemoveWindowFromColumns (w);
  1632.     DeletePrivateWindowData (w);
  1633.     OriginalKillTextWindow (w);
  1634.     }
  1635.  
  1636. /*
  1637.  * This gets called at startup.
  1638.  * Change the QUED bottlenecks, and insert our own menu items into one of the menus.
  1639.  */
  1640. void
  1641. _main (void)
  1642.     {
  1643.     int    newMenuID;
  1644.  
  1645.     /*
  1646.      * Install some of our functions in place of QUEDs bottlenecks.  Note that "Q" is a pointer
  1647.      * to the ORIGINAL bottlenecks.
  1648.      */
  1649.  
  1650.     /*
  1651.      * We want to save and read in our settings for "diff" into the preferences file.
  1652.      */
  1653.     OriginalReadPreferences = ReadPreferences;
  1654.     ReadPreferences = DiffReadPreferences;
  1655.     
  1656.     /*
  1657.      * We need to override how text markers are modified when text is moved.  Remember to
  1658.      * offset our change bars as well.
  1659.      */
  1660.     OriginalOffsetTextMarkers = OffsetTextMarkers;
  1661.     OffsetTextMarkers = DiffOffsetTextMarkers;
  1662.     
  1663.     /*
  1664.      * We need to tell QUED to show the change bars on the left side.
  1665.      */
  1666.     OriginalShowLeftMarginIcons = ShowLeftMarginIcons;
  1667.     ShowLeftMarginIcons = DiffShowLeftMarginIcons;
  1668.  
  1669.     /*
  1670.      * Tell QUED how to compute the total width of all the icons on the left side of the text.
  1671.      */
  1672.     OriginalGetQuedIconsWidth = GetQuedIconsWidth;
  1673.     GetQuedIconsWidth = DiffGetQuedIconsWidth;
  1674.  
  1675.     /*
  1676.      * Tell QUED how to handle clicks on the icon area to the left of the text.
  1677.      */
  1678.     OriginalClickLeftMarginIcons = ClickLeftMarginIcons;
  1679.     ClickLeftMarginIcons = DiffClickLeftMarginIcons;
  1680.  
  1681.     /*
  1682.      * We need to tell QUED to dispose all our additional stuff whenever it wants to close a window.
  1683.      */
  1684.     OriginalKillTextWindow = KillTextWindow;
  1685.     KillTextWindow = DiffKillTextWindow;
  1686.  
  1687.     /*
  1688.      * Now, insert the menu items.
  1689.      */
  1690.     newMenuID = 260;    /* The "memory" menu */
  1691.     InsertQuedMenuItem (&newMenuID, 13, "\p", "\p2-File Differences", 'DIFF', 0, DoDiffMenu2, NULL, NULL, 0/* MS_TwoTextWindows | MS_NoModalDialog */);
  1692.     InsertQuedMenuItem (&newMenuID, 14, "\p", "\p3-File Differences", 'DIFF', 1, DoDiffMenu3, NULL, NULL, 0/* MS_TwoTextWindows | MS_NoModalDialog */);
  1693.     InsertQuedMenuItem (&newMenuID, 15, "\p", "\pDifferences Options…", 'DIFF', 2, DoDiffOptions, NULL, NULL, 0/* MS_TwoTextWindows | MS_NoModalDialog */);
  1694.     }
  1695.  
  1696. /*
  1697.  * All of the following routines are to modify the behavior of UNIX Diff.  These are routines
  1698.  * that they call from stdio, which we needed to override because QUED doesn't have stdio.
  1699.  * Stdio instead appends the output to "outFileHandle".
  1700.  */
  1701. size_t
  1702. fwrite (const void *p, size_t len, size_t size, FILE *outfile)
  1703.     {
  1704.     long    retval;
  1705.     
  1706.     retval = (long)len * (long)size;
  1707.     PtrAndHand (p, outFileHandle, retval);
  1708.     return (retval);
  1709.     }
  1710.  
  1711. static    void
  1712. ConvertNewLines (char *xstr)
  1713.     {
  1714.     register char *str = xstr;
  1715.     
  1716.     while (*str != '\0')
  1717.         if (*str++ == '\n')
  1718.             str[-1] = '\r';
  1719.     }
  1720.  
  1721. int
  1722. fprintf (FILE *outfile, const char *fmt, ...)
  1723.     {
  1724.     va_list    arglist;
  1725.     char    outStr[256];
  1726.     long    arg1, arg2, arg3, arg4;
  1727.     char    fmtStr[256];
  1728.     
  1729.     va_start (arglist, fmt);
  1730.     
  1731.     strncpy (fmtStr, fmt, 256);
  1732.     ConvertNewLines (fmtStr);
  1733.     
  1734.     arg1 = va_arg(arglist, long);
  1735.     arg2 = va_arg(arglist, long);
  1736.     arg3 = va_arg(arglist, long);
  1737.     arg4 = va_arg(arglist, long);
  1738.     Qued_sprintf(outStr, fmtStr, arg1, arg2, arg3, arg4);
  1739.     fwrite (outStr, (size_t)1, (size_t)strlen(outStr), outfile);
  1740.     va_end (arglist);
  1741.     return (0);
  1742.     }
  1743.  
  1744. int
  1745. printf (const char *fmt, ...)
  1746.     {
  1747.     va_list    arglist;
  1748.     char    outStr[256];
  1749.     long    arg1, arg2, arg3, arg4;
  1750.     char    fmtStr[256];
  1751.     
  1752.     va_start (arglist, fmt);
  1753.     
  1754.     strncpy (fmtStr, fmt, 256);
  1755.     ConvertNewLines (fmtStr);
  1756.     
  1757.     arg1 = va_arg(arglist, long);
  1758.     arg2 = va_arg(arglist, long);
  1759.     arg3 = va_arg(arglist, long);
  1760.     arg4 = va_arg(arglist, long);
  1761.     Qued_sprintf(outStr, fmtStr, arg1, arg2, arg3, arg4);
  1762.     fwrite (outStr, (size_t)1, (size_t)strlen(outStr), NULL);
  1763.     va_end (arglist);
  1764.     return (0);
  1765.     }
  1766.  
  1767. int
  1768. __putc (int ch, FILE *outfile)
  1769.     {
  1770.     char    c = ch;
  1771.     
  1772.     fwrite (&c, (size_t)1, (size_t)1, outfile);
  1773.     if ( outfile != NULL )
  1774.         outfile->cnt = 0;    /* Reset the counter to 0; there is no buffer. */
  1775.     return (0);
  1776.     }
  1777.  
  1778.  
  1779.  
  1780. int    errno;
  1781.  
  1782. /* malloc a block of memory, with fatal error message if we can't do it. */
  1783.  
  1784. void *
  1785. malloc (size)
  1786.     size_t size;
  1787. {
  1788.     register void *value;
  1789.     
  1790.     ResrvMem ((long)size);
  1791.     
  1792.     value = (void *) NewHandleClear ((long)size);
  1793.     if ( value )
  1794.     {
  1795.         allocatedBlocks++;
  1796.         HLock (value);
  1797.         value = *(Handle)value;
  1798.     }
  1799.     else
  1800.     {
  1801.         if ( ! errno )
  1802.             errno = MemErr;
  1803.     }
  1804.     return value;
  1805. }
  1806.  
  1807. /* malloc a block of memory, with fatal error message if we can't do it. */
  1808.  
  1809. void *
  1810. xmalloc (size)
  1811.     size_t size;
  1812. {
  1813.     void *value = malloc((size_t)size);
  1814.     
  1815.     /* Display an error message if NIL */
  1816.     return (value);
  1817. }
  1818.  
  1819. /* realloc a block of memory, with fatal error message if we can't do it. */
  1820.  
  1821. void *
  1822. realloc (old, size)
  1823.     void *old;
  1824.     size_t  size;
  1825. {
  1826.     old = RecoverHandle(old);
  1827.     if ( MemErr )
  1828.     {
  1829. #ifdef    DEBUGGING
  1830.         DebugStr ("\pFATAL realloc: Cannot RecoverHandle!");
  1831. #endif
  1832.         goto    err;
  1833.     }
  1834.     if ( old )
  1835.     {
  1836.         HUnlock (old);
  1837.         if ( size > GetHandleSize(old))
  1838.             ResrvMem ((long)size);
  1839.         SetHandleSize (old, (long)size);
  1840.         if ( ! MemErr )
  1841.         {
  1842.             HLock (old);
  1843.             old = *(Handle)old;
  1844.             return (old);
  1845.         }
  1846.         DisposHandle (old);
  1847.         if ( MemErr )
  1848.         {
  1849. #ifdef    DEBUGGING
  1850.             DebugStr ("\pFATAL realloc: Cannot DisposHandle!");
  1851. #endif
  1852.             goto    err;
  1853.         }
  1854.         allocatedBlocks--;
  1855.     }
  1856. err:
  1857.     if ( ! errno )
  1858.         errno = MemErr;
  1859.     return (NULL);
  1860. }
  1861.  
  1862. /* realloc a block of memory, with fatal error message if we can't do it. */
  1863.  
  1864. void *
  1865. xrealloc (old, size)
  1866.     void *old;
  1867.     size_t size;
  1868. {
  1869.     old = realloc(old, (size_t)size);
  1870.     
  1871.     /* Display an error message if NIL */
  1872.     return (old);
  1873. }
  1874.  
  1875. void *
  1876. xcalloc (nitems, size)
  1877.     size_t nitems;
  1878.     size_t size;
  1879. {
  1880.     register void *value;
  1881.     
  1882.     ResrvMem ((long)size);
  1883.     
  1884.     value = (void *) NewHandleClear ((long)size * (long)nitems);
  1885.     if ( value )
  1886.     {
  1887.         allocatedBlocks++;
  1888.         HLock (value);
  1889.         value = *(Handle)value;
  1890.     }
  1891.     else
  1892.     {
  1893.         if ( ! errno )
  1894.             errno = MemErr;
  1895.     }
  1896.     return value;
  1897. }
  1898.  
  1899. void
  1900. free(void *p)
  1901.     {
  1902.     if ( ! p )
  1903.         return;
  1904.     p = RecoverHandle(p);
  1905.     if ( MemErr )
  1906.     {
  1907. #ifdef    DEBUGGING
  1908.         DebugStr ("\pFATAL free: Cannot RecoverHandle!");
  1909. #endif
  1910.         return;
  1911.     }
  1912.     if ( p )
  1913.     {
  1914.         DisposHandle (p);
  1915.         if ( MemErr )
  1916.         {
  1917. #ifdef    DEBUGGING
  1918.             DebugStr ("\pFATAL free: Cannot DisposHandle!");
  1919. #endif
  1920.             return;
  1921.         }
  1922.         allocatedBlocks--;
  1923.     }
  1924.     }
  1925.  
  1926.  
  1927. char *
  1928. ctime(const time_t *timer)
  1929.     {
  1930.     static    char    timeStr[256];
  1931.     char    tempTime[256];
  1932.     
  1933.     IUTimeString (*timer, TRUE, (unsigned char *)tempTime);
  1934.     IUDateString (*timer, 0, (unsigned char *)timeStr);
  1935.     PtoCstr ((void *)tempTime);
  1936.     PtoCstr ((void *)timeStr);
  1937.     strcat (timeStr, " ");
  1938.     strcat (timeStr, tempTime);
  1939.     return (timeStr);
  1940.     }
  1941.  
  1942. void
  1943. fatal(char *strMessage)
  1944.     {
  1945.     message ("%s", strMessage, NULL);
  1946.     print_message_queue ();
  1947.     }
  1948.  
  1949.  
  1950. /* Call before outputting the results of comparing files NAME0 and NAME1
  1951.    to set up OUTFILE, the stdio stream for the output to go to.
  1952.  
  1953.    Usually, OUTFILE is just stdout.  But when -l was specified
  1954.    we fork off a `pr' and make OUTFILE a pipe to it.
  1955.    `pr' then outputs to our stdout.  */
  1956.  
  1957. void
  1958. setup_output (name0, name1, depth)
  1959.     char *name0, *name1;
  1960.     int depth;
  1961. {
  1962.     /* Don't do anything on the Mac. */
  1963. }
  1964.  
  1965. /* Call after the end of output of diffs for one file.
  1966.    Close OUTFILE and get rid of the `pr' subfork.  */
  1967.  
  1968. void
  1969. finish_output ()
  1970. {
  1971.     /* Don't do anything on the Mac. */
  1972. }
  1973.  
  1974. /* Use when a system call returns non-zero status and that is fatal.  */
  1975.  
  1976. void
  1977. pfatal_with_name (text)
  1978.      char *text;
  1979. {
  1980.     message ("%s: ", text, NULL);
  1981.     print_message_queue ();
  1982. }
  1983.